#include "Vector3.h"
#include "Vector4.h"
#include "Matrix4.h"

#include <math.h>

#pragma once

namespace CoreMath
{
	Matrix4 GetTranslationMatrix(real dX, real dY, real dZ)
	{
		real rawValue[4][4] =
		{
			1,		0,		0,		dX,
			0,		0,		0,		dY,
			0,		0,		0,		dZ,
			0,		0,		0,		1
		};

		return Matrix4(rawValue);
	}

	Matrix4 GetScalingMatrix(real scaleX, real scaleY, real scaleZ)
	{
		real rawValue[4][4] =
		{
			scaleX,	0,		0,		0,
			0,		scaleY, 0,		0,
			0,		0,		scaleZ, 0,
			0,		0,		0,		1
		};

		return Matrix4(rawValue);
	}

	Matrix4 GetRotationMatrix(real angleX, real angleY, real angleZ)
	{
		real cosX = cos(angleX);
		real cosY = cos(angleY);
		real cosZ = cos(angleZ);

		real sinX = sin(angleX);
		real sinY = sin(angleY);
		real sinZ = sin(angleZ);


		real rawValue[4][4] =
		{
			cosY*cosZ,		cosZ*sinX*sinY - cosX*sinZ,		cosX*cosZ*sinY + sinX*sinZ,		0,
			cosY*cosZ,		cosX*cosZ + sinX * sinY * sinZ,	-cosZ*sinX + cosX*sinY*sinZ,	0,
			-sinY,			cosY*sinX,						cosX*cosY,						0,
			0,				0,								0,								1
		};

		return Matrix4(rawValue);
	}

	Matrix4 GetShearingMatrix(const real shearX, const real shearY, const real shearZ, const real shearXY)
	{
		real rawValue[4][4] = 
		{
			shearX,		shearXY,		0,			0,
			0,			shearY,			0,			0,
			0,			0,				shearZ,		0,
			0,			0,				0,			1
		};

		return Matrix4(rawValue);
	}

	Matrix4 GetReflectionMatrix(const Vector4& direction)
	{
		real rawValue[4][4] =
		{
			1 - (2 * pow(direction.i, 2)),			-2 * (direction.i * direction.j),		-2 * (direction.i * direction.k),		0,
			-2 * (direction.i * direction.j),		1 - (2 * pow(direction.j, 2)), -		2 * (direction.j * direction.k),		0,
			-2 * (direction.i * direction.k),		-2 * (direction.j * direction.k),		1 - (2 * pow(direction.k, 2)),			0,
			0,										0,										0,										1
		};

		return Matrix4(rawValue);
	}

	void Translate(Vector4& vector, const real dX, const real dY, const real dZ)
	{
		Matrix4 m_TransformationMatrix = GetTranslationMatrix(dX, dY, dZ);
		vector = m_TransformationMatrix * vector;
	}

	void Rotate(Vector4& vector, const real angleX, const real angleY, const real angleZ)
	{
		Matrix4 m_TransformationMatrix = GetRotationMatrix(angleX, angleY, angleZ);
		vector = m_TransformationMatrix * vector;
	}

	void Scale(Vector4& vector, const real scaleX, const real scaleY, const real scaleZ)
	{
		Matrix4 m_TransformationMatrix = GetScalingMatrix(scaleX, scaleY, scaleZ);
		vector = m_TransformationMatrix * vector;
	}

	void Shear(Vector4& vector, const real shearX, const real shearY, const real shearZ, const real shearXY)
	{
		vector = GetShearingMatrix(shearX, shearY, shearZ, shearXY) * vector;
	}

	void Reflect(Vector4& vector, const Vector4& direction)
	{
		vector = GetReflectionMatrix(direction) * vector;
	}
}